﻿{***************************************************************************}
{                                                                           }
{           Spring Framework for Delphi                                     }
{                                                                           }
{           Copyright (C) 2009-2010 DevJet                                  }
{                                                                           }
{           http://www.spring4d.org                                         }
{                                                                           }
{***************************************************************************}
{                                                                           }
{  Licensed under the Apache License, Version 2.0 (the "License");          }
{  you may not use this file except in compliance with the License.         }
{  You may obtain a copy of the License at                                  }
{                                                                           }
{      http://www.apache.org/licenses/LICENSE-2.0                           }
{                                                                           }
{  Unless required by applicable law or agreed to in writing, software      }
{  distributed under the License is distributed on an "AS IS" BASIS,        }
{  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
{  See the License for the specific language governing permissions and      }
{  limitations under the License.                                           }
{                                                                           }
{***************************************************************************}

unit Spring.Tests.Serialization;

interface

uses
  SysUtils,
  TypInfo,
  Dialogs,
  Classes,
  Rtti,
  TestFramework,
  Generics.Collections,
  Spring.Collections,
  Spring.Serialization,
  Spring.Serialization.Formatter.XMLDocument,
  Spring.UnitTests;

type
  TTestClass = class;

  TTestSerialization = class(TTestCase)
  private
    fSerializer: ISerializer;
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestSerializeRecord;
    procedure TestSerializeRecordToFile;
    procedure TestDeserializeRecord;
    procedure TestDeserializeRecordFromFile;
    procedure TestSerializeClassAndScalars;
    procedure TestSerializeClassAndScalarsToFile;
    procedure TestDeserializeClassAndScalars;
    procedure TestDeserializeClassAndScalarsFromFile;
    procedure TestSerializeInterfaceAndScalars;
    procedure TestDeserializeInterfaceAndScalars;
    procedure TestSerializeInterfaceAndScalarsToFile;
    procedure TestDeserializeInterfaceAndScalarsFromFile;
    procedure TestDeserializeClassFromScrach;
    procedure TestDeserializeInterfaceFromScrach;
    procedure TestSerializeGenericCollectionWithPrimitivesToFile;
    procedure TestSerializeGenericCollectionWithClassToFile;
    procedure TestDeserializeGenericCollectionWithPrimitivesFromFile;
    procedure TestDeserializeGenericCollectionWithClassFromFile;
    procedure TestSerializeInterfacedCollection;
    procedure TestSerializeInterfacedCollectionToFile;
    procedure TestDeserializeInterfacedCollection;
    procedure TestDeserializeInterfacedCollectionFromFile;

    procedure TestSerializeFont;
    procedure TestSerializeArray;
    procedure TestDeserializeArray;
  end;

  ITestClass = interface(IInvokable)
    ['{3A988458-3483-4BA2-A48C-A596073B911F}']
    {$REGION 'Property Accessors'}
      function GetEnabled: Boolean;
      function GetIndex: Integer;
      function GetName: string;
      function GetChildren: IList<ITestClass>;
      function GetGenericListWithPrimitives: TList<Integer>;
      function GetGenericListWithClass: TList<TTestClass>;
      procedure SetEnabled(const value: Boolean);
      procedure SetIndex(const value: Integer);
      procedure SetName(const value: string);
    {$ENDREGION}

    property Name: string read GetName write SetName;
    property Index: Integer read GetIndex write SetIndex;
    property Enabled: Boolean read GetEnabled write SetEnabled;
    property Children: IList<ITestClass> read GetChildren;
    property GenericListWithPrimitives: TList<Integer> read GetGenericListWithPrimitives;
    property GenericListWithClass: TList<TTestClass> read GetGenericListWithClass;
  end;

  TTestClass = class(TInterfacedObject, ITestClass)
  private
    fName: string;
    fEnabled: Boolean;
    fIndex: Integer;
    fThis: TTestClass;
    fChildren: IList<ITestClass>;
    fGenericListWithPrimitives: TList<Integer>;
    fGenericListWithClass: TList<TTestClass>;

    {$REGION 'Property Accessors'}
      function GetEnabled: Boolean;
      function GetIndex: Integer;
      function GetName: string;
      function GetChildren: IList<ITestClass>;
      function GetGenericListWithPrimitives: TList<Integer>;
      function GetGenericListWithClass: TList<TTestClass>;
      procedure SetEnabled(const value: Boolean);
      procedure SetIndex(const value: Integer);
      procedure SetName(const value: string);
    {$ENDREGION}
  public
    destructor Destroy; override;
    property Name: string read GetName write SetName;
    property Index: Integer read GetIndex write SetIndex;
    property Enabled: Boolean read GetEnabled write SetEnabled;
    property This: TTestClass read fThis write fThis;
    property Children: IList<ITestClass> read GetChildren;
    property GenericListWithPrimitives: TList<Integer> read GetGenericListWithPrimitives;
    property GenericListWithClass: TList<TTestClass> read GetGenericListWithClass;
  end;

  TEnum = (teTiger, teLion, teFrog, teAligator, teCat, teDog);

  TSet = set of TEnum;

  TTestRecord = record
  public
    fName: string;
    fEnabled: Boolean;
    fIndex: Integer;
    fEnum: TEnum;
    fSet: TSet;
  private
    function GetEnabled: Boolean;
    function GetIndex: Integer;
    function GetName: string;
    procedure SetEnabled(const value: Boolean);
    procedure SetIndex(const value: Integer);
    procedure SetName(const value: string);
  public
    property Name: string read GetName write SetName;
    property Index: Integer read GetIndex write SetIndex;
    property Enabled: Boolean read GetEnabled write SetEnabled;
    property Enum: TEnum read fEnum write fEnum;
    property SimpleSet: TSet read fSet write fSet;
  end;

  TArrayClass = class
  private
    fNumbers: TArray<Integer>;
  public
    constructor Create; overload;
    constructor Create(const count: Integer); overload;

    property Numbers: TArray<Integer> read fNumbers;
  end;

implementation

uses
  Forms,
  Graphics,
  Spring.Reflection,
  Spring.Reflection.ValueConverters;

{ TTestSerialization }

procedure TTestSerialization.SetUp;
begin
  inherited;
  fSerializer := TSerializer.Create;
  fSerializer.Backend := TXmlFormatter.Create;
end;

procedure TTestSerialization.TearDown;
begin
  inherited;
  fSerializer := nil;
end;

procedure TTestSerialization.TestSerializeInterfaceAndScalars;
var
  instance: ITestClass;
  content: string;
begin
  instance := TTestClass.Create;
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;

  content := fSerializer.Serialize(TValue.From<ITestClass>(instance));
  CheckNotEqualsString('', content, 'Serialize content cannot be empty.');
end;

procedure TTestSerialization.TestSerializeInterfaceAndScalarsToFile;
var
  instance: ITestClass;
begin
  instance := TTestClass.Create;
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;

  fSerializer.SerializeToFile(TValue.From<ITestClass>(instance), 'InterfaceToFile.xml');
  CheckTrue(FileExists('InterfaceToFile.xml'));
end;

procedure TTestSerialization.TestDeserializeInterfaceAndScalars;
var
  instance: ITestClass;
  content: string;
begin
  instance := TTestClass.Create;

  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                 '<This type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                   '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                     '<Collection.Items/>' +
                   '</Children>' +
                 '</This>' +
                 '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</Children>' +
                 '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithPrimitives>' +
                 '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithClass>' +
               '</Reference>' +
             '</Root>';

  fSerializer.Deserialize(TValue.From<ITestClass>(instance), content);

  CheckEqualsString('Test12', instance.Name);
  CheckFalse(instance.Enabled);
  CheckEquals(instance.Index, 128);
end;

procedure TTestSerialization.TestDeserializeInterfaceAndScalarsFromFile;
var
  instance: ITestClass;
begin
  instance := TTestClass.Create;

  fSerializer.DeserializeFromFile(TValue.From<ITestClass>(instance), 'InterfaceToFile.xml');

  CheckEqualsString('Test', instance.Name);
  CheckTrue(instance.Enabled);
  CheckEquals(instance.Index, 102);
end;

procedure TTestSerialization.TestDeserializeClassFromScrach;
var
  value: TValue;
  instance: TTestClass;
  content: string;
begin
  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                 '<This type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                   '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                     '<Collection.Items/>' +
                   '</Children>' +
                 '</This>' +
                 '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</Children>' +
                 '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithPrimitives>' +
                 '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithClass>' +
               '</Reference>' +
             '</Root>';

  value := fSerializer.Deserialize(content);
  CheckFalse(value.IsEmpty);

  CheckTrue(value.IsObject);
  instance := value.AsObject as TTestClass;
  CheckEqualsString('Test12', instance.Name);
  CheckFalse(instance.Enabled);
  CheckEquals(instance.Index, 128);

  instance.Free;
end;

procedure TTestSerialization.TestDeserializeInterfaceFromScrach;
var
  value: TValue;
  instance: ITestClass;
  content: string;
begin
  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                 '<This type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Test12" Index="128">' +
                   '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                     '<Collection.Items/>' +
                   '</Children>' +
                 '</This>' +
                 '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</Children>' +
                 '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithPrimitives>' +
                 '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithClass>' +
               '</Reference>' +
             '</Root>';

  value := fSerializer.Deserialize(content);
  CheckFalse(value.IsEmpty);

  CheckTrue(Supports(value.AsObject, ITestClass, instance));
  CheckEqualsString('Test12', instance.Name);
  CheckFalse(instance.Enabled);
  CheckEquals(instance.Index, 128);
end;

procedure TTestSerialization.TestDeserializeRecord;
var
  instance: TValue;
  content: string;
begin
  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestRecord" fName="Test" fEnabled="True" fIndex="102" fEnum="teFrog" fSet="[teLion,teCat,teDog]"/>' +
             '</Root>';

  instance := fSerializer.Deserialize(content);

  CheckTrue(instance.Kind in [tkRecord]);
  CheckTrue(instance.AsType<TTestRecord>.Enabled);
  CheckEquals('Test', instance.AsType<TTestRecord>.Name);
  CheckEquals(102, instance.AsType<TTestRecord>.Index);
  CheckTrue([teLion,teCat,teDog] = instance.AsType<TTestRecord>.SimpleSet);
end;

procedure TTestSerialization.TestDeserializeRecordFromFile;
var
  instance: TValue;
begin
  instance := fSerializer.DeserializeFromFile('RecordToFile.xml');

  CheckTrue(instance.Kind in [tkRecord]);
  CheckTrue(instance.AsType<TTestRecord>.Enabled);
  CheckEquals('Test', instance.AsType<TTestRecord>.Name);
  CheckEquals(102, instance.AsType<TTestRecord>.Index);
  CheckEquals(Ord(teFrog), Ord(instance.AsType<TTestRecord>.Enum));
  CheckTrue([teLion,teCat,teDog] = instance.AsType<TTestRecord>.SimpleSet);
end;

procedure TTestSerialization.TestSerializeArray;
var
  instance: TArrayClass;
begin
  instance := TArrayClass.Create(2);

  fSerializer.SerializeToFile(instance, 'ArrayToFile.xml');
  instance.Free;
end;

procedure TTestSerialization.TestDeserializeArray;
var
  instance: TArrayClass;
begin
  instance := TArrayClass.Create;

  fSerializer.DeserializeFromFile(instance, 'ArrayToFile.xml');
  instance.Free;
end;

procedure TTestSerialization.TestSerializeClassAndScalars;
var
  instance: TTestClass;
  content: string;
begin
  instance := TTestClass.Create;
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;
  instance.This := instance;

  content := fSerializer.Serialize(TValue.From<TTestClass>(instance));
  CheckNotEqualsString('', content, 'Serialize content cannot be empty.');

  instance.Free;
end;

procedure TTestSerialization.TestSerializeClassAndScalarsToFile;
var
  instance: TTestClass;
begin
  instance := TTestClass.Create;
  instance.Name := 'TestName';
  instance.Enabled := True;
  instance.Index := 102;
  instance.This := instance;

  fSerializer.SerializeToFile(TValue.From<TTestClass>(instance), 'ClassToFile.xml');
  CheckTrue(FileExists('ClassToFile.xml'));

  instance.Free;
end;

procedure TTestSerialization.TestSerializeFont;
var
  font: TFont;
begin
  font := TFont.Create;

  fSerializer.SerializeToFile(font, 'FontToFile.xml');
  font.Free;
end;

procedure TTestSerialization.TestSerializeGenericCollectionWithPrimitivesToFile;
var
  instance: TTestClass;
begin
  instance := TTestClass.Create;
  instance.Name := 'TestName';
  instance.Enabled := True;
  instance.Index := 102;
  instance.This := instance;

  instance.GenericListWithPrimitives.Add(1);
  instance.GenericListWithPrimitives.Add(5);
  instance.GenericListWithPrimitives.Add(12);

  fSerializer.SerializeToFile(TValue.From<TTestClass>(instance), 'GenericCollectionWithPrimitivesToFile.xml');
  CheckTrue(FileExists('GenericCollectionWithPrimitivesToFile.xml'));

  instance.Free;
end;

procedure TTestSerialization.TestDeserializeGenericCollectionWithPrimitivesFromFile;
var
  instance: TTestClass;
begin
  instance := TTestClass.Create;

  fSerializer.DeserializeFromFile(instance, 'GenericCollectionWithPrimitivesToFile.xml');

  CheckEqualsString('TestName', instance.Name);
  CheckTrue(instance.Enabled);
  CheckEquals(instance.Index, 102);
  CheckEquals(3, instance.GenericListWithPrimitives.Count);
  CheckEquals(1, instance.GenericListWithPrimitives[0]);
  CheckEquals(5, instance.GenericListWithPrimitives[1]);
  CheckEquals(12, instance.GenericListWithPrimitives[2]);

  instance.Free;
end;

procedure TTestSerialization.TestSerializeGenericCollectionWithClassToFile;
var
  parent, child: TTestClass;
begin
  parent := TTestClass.Create;
  parent.Name := 'TestName';
  parent.Enabled := True;
  parent.Index := 102;
  parent.This := parent;

  child := TTestClass.Create;
  child.Name := 'Child 1';
  child.Enabled := True;
  child.Index := 2898;
  child.This := child;
  parent.GenericListWithClass.Add(child);

  child := TTestClass.Create;
  child.Name := 'Child 2';
  child.Enabled := False;
  child.Index := 2765;
  child.This := child;
  parent.GenericListWithClass.Add(child);

  fSerializer.SerializeToFile(TValue.From<TTestClass>(parent), 'GenericCollectionWithClassToFile.xml');
  CheckTrue(FileExists('GenericCollectionWithClassToFile.xml'));

  parent.Free;
end;

procedure TTestSerialization.TestDeserializeGenericCollectionWithClassFromFile;
var
  instance: TTestClass;
begin
  instance := TTestClass.Create;

  fSerializer.DeserializeFromFile(instance, 'GenericCollectionWithClassToFile.xml');

  CheckEqualsString('TestName', instance.Name);
  CheckTrue(instance.Enabled);
  CheckEquals(instance.Index, 102);
  CheckEquals(2, instance.GenericListWithClass.Count);

  CheckEquals('Child 1', instance.GenericListWithClass[0].Name);
  CheckTrue(instance.GenericListWithClass[0].Enabled);
  CheckEquals(2898, instance.GenericListWithClass[0].Index);

  CheckEquals('Child 2', instance.GenericListWithClass[1].Name);
  CheckFalse(instance.GenericListWithClass[1].Enabled);
  CheckEquals(2765, instance.GenericListWithClass[1].Index);
  instance.Free;
end;

procedure TTestSerialization.TestDeserializeClassAndScalars;
var
  instance: TTestClass;
  content: string;
begin
  instance := TTestClass.Create;

  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestClass" Enabled="True" Name="TestName" Index="102">' +
                 '<This type="Spring.Tests.Serialization.TTestClass" Enabled="True" Name="TestName" Index="102">' +
                   '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                     '<Collection.Items/>' +
                   '</Children>' +
                 '</This>' +
                 '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</Children>' +
                 '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithPrimitives>' +
                 '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithClass>' +
               '</Reference>' +
             '</Root>';

  fSerializer.Deserialize(instance, content);

  CheckEqualsString('TestName', instance.Name);
  CheckTrue(instance.Enabled);
  CheckEquals(instance.Index, 102);
  CheckNull(instance.This, 'Circular reference are not supported.');

  instance.Free;
end;

procedure TTestSerialization.TestDeserializeClassAndScalarsFromFile;
var
  instance: TTestClass;
begin
  instance := TTestClass.Create;

  fSerializer.DeserializeFromFile(TValue.From<TTestClass>(instance), 'ClassToFile.xml');
  CheckEquals('TestName', instance.Name);
  CheckTrue(instance.Enabled);
  CheckEquals(102, instance.Index);
  CheckNull(instance.This, 'Circular reference are not supported.');

  instance.Free;
end;

procedure TTestSerialization.TestSerializeInterfacedCollection;
var
  instance, child: ITestClass;
  content: string;
begin
  instance := TTestClass.Create;
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;

  child := TTestClass.Create;
  child.Name := 'Children of Test';
  child.Enabled := False;
  child.Index := 110022;

  instance.Children.Add(child);

  content := fSerializer.Serialize(TValue.From<ITestClass>(instance));
  CheckNotEqualsString('', content, 'Serialize content cannot be empty.');
end;

procedure TTestSerialization.TestSerializeInterfacedCollectionToFile;
var
  instance, child: ITestClass;
begin
  instance := TTestClass.Create;
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;

  child := TTestClass.Create;
  child.Name := 'Children of Test';
  child.Enabled := False;
  child.Index := 110022;

  instance.Children.Add(child);

  fSerializer.SerializeToFile(TValue.From<ITestClass>(instance), 'InterfacedCollectionToFile.xml');
end;

procedure TTestSerialization.TestSerializeRecord;
var
  instance: TTestRecord;
  content: string;
begin
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;
  instance.Enum := teFrog;
  instance.SimpleSet := [teDog, teCat, teLion];

  content := fSerializer.Serialize(TValue.From<TTestRecord>(instance));
end;

procedure TTestSerialization.TestSerializeRecordToFile;
var
  instance: TTestRecord;
begin
  instance.Name := 'Test';
  instance.Enabled := True;
  instance.Index := 102;
  instance.Enum := teFrog;
  instance.SimpleSet := [teDog, teCat, teLion];

  fSerializer.SerializeToFile(TValue.From<TTestRecord>(instance), 'RecordToFile.xml');
end;

procedure TTestSerialization.TestDeserializeInterfacedCollection;
var
  instance: ITestClass;
  content: string;
begin
  instance := TTestClass.Create;

  content := '<?xml version="1.0"?>' +
             '<Root>' +
               '<Reference type="Spring.Tests.Serialization.TTestClass" Enabled="True" Name="Test" Index="102">' +
                 '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                   '<Collection.Items>' +
                     '<Item type="Spring.Tests.Serialization.TTestClass" Enabled="False" Name="Children of Test" Index="110022">' +
                       '<Children type="Spring.Tests.Serialization.IList&lt;Spring.Tests.Serialization.ITestClass&gt;">' +
                         '<Collection.Items/>' +
                       '</Children>' +
                       '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                         '<Collection.Items/>' +
                       '</GenericListWithPrimitives>' +
                       '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                         '<Collection.Items/>' +
                       '</GenericListWithClass>' +
                     '</Item>' +
                   '</Collection.Items>' +
                 '</Children>' +
                 '<GenericListWithPrimitives type="Spring.Tests.Serialization.TList&lt;System.Integer&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithPrimitives>' +
                 '<GenericListWithClass type="Spring.Tests.Serialization.TList&lt;Spring.Tests.Serialization.TTestClass&gt;">' +
                   '<Collection.Items/>' +
                 '</GenericListWithClass>' +
               '</Reference>' +
             '</Root>';

  fSerializer.Deserialize(TValue.From<ITestClass>(instance), content);

  CheckFalse(instance.Children.IsEmpty);
  CheckEquals(1, instance.Children.Count);
  CheckEquals('Children of Test', instance.Children[0].Name);
  CheckFalse(instance.Children[0].Enabled);
  CheckEquals(110022, instance.Children[0].Index);
end;

procedure TTestSerialization.TestDeserializeInterfacedCollectionFromFile;
begin

end;

{ TTestClass }

destructor TTestClass.Destroy;
begin
  if Assigned(fGenericListWithPrimitives) then
    fGenericListWithPrimitives.Free;

  if Assigned(fGenericListWithClass) then
    fGenericListWithClass.Free;
  inherited;
end;

function TTestClass.GetChildren: IList<ITestClass>;
begin
  if not Assigned(fChildren) then
    fChildren := TCollections.CreateList<ITestClass>;

  Result := fChildren;
end;

function TTestClass.GetEnabled: boolean;
begin
  Result := fEnabled;
end;

function TTestClass.GetGenericListWithClass: TList<TTestClass>;
begin
  if not Assigned(fGenericListWithClass) then
    fGenericListWithClass := TObjectList<TTestClass>.Create;

  Result := fGenericListWithClass;
end;

function TTestClass.GetGenericListWithPrimitives: TList<Integer>;
begin
  if not Assigned(fGenericListWithPrimitives) then
    fGenericListWithPrimitives := TList<Integer>.Create;

  Result := fGenericListWithPrimitives;
end;

function TTestClass.GetIndex: integer;
begin
  Result := fIndex;
end;

function TTestClass.GetName: string;
begin
  Result := fName;
end;

procedure TTestClass.SetEnabled(const Value: boolean);
begin
  fEnabled := Value;
end;

procedure TTestClass.SetIndex(const Value: integer);
begin
  fIndex := Value;
end;

procedure TTestClass.SetName(const Value: string);
begin
  fName := Value;
end;

{ TTestRecord }

function TTestRecord.GetEnabled: Boolean;
begin
  Result := fEnabled;
end;

function TTestRecord.GetIndex: Integer;
begin
  Result := fIndex;
end;

function TTestRecord.GetName: string;
begin
  Result := fName;
end;

procedure TTestRecord.SetEnabled(const value: Boolean);
begin
  fEnabled := Value
end;

procedure TTestRecord.SetIndex(const value: Integer);
begin
  fIndex := value;
end;

procedure TTestRecord.SetName(const value: string);
begin
  fName := value;
end;

{ TArrayClass }

constructor TArrayClass.Create;
begin
  fNumbers := nil;
end;

constructor TArrayClass.Create(const count: Integer);
begin
  SetLength(fNumbers, count);
end;

end.
